/**
 * @copyright Copyright (c) 2023..
 *
 * @file    save.c
 * @brief
 * @author  xuesong(wenshaoliu@foxmail.com)
 * @version 0.1
 * @date    2023-04-21
 */
#include "save.h"
// #include "user_data.h"
#include <stdio.h>
#include <string.h>
#include "rtc.h"

#include "flashdb.h"
#include "fdb_def.h"
#include "OSAL_Memory.h"
// #include "Pillow.h"
#include "types.h"
#include "bcomdef.h"
// #include "simpleBLEPeripheral.h"
// #include "user_prcess.h"

struct fdb_tsdb xTsdb;
struct fdb_kvdb xKvdb;
struct fdb_kvdb xKvdbUserInfor;

static struct fdb_default_kv_node default_kv_table[] = {
    {"root", "123", 0}, /* string KV */
};

/**
 * @fn
 * @brief Return value must is real UTC value.
 * @param
 * @return   */
fdb_time_t uxTimeStampGet(void)
{
    uint32 ulUtc;
    ulUtc = HalRtcGet_Utc();
    return (fdb_time_t)ulUtc;
}

/**
 * @fn
 * @brief * @param
 * @return   */
void FlashDdInit(void)
{
    //	fdb_err_t result;
    struct fdb_default_kv default_kv;

    default_kv.kvs = default_kv_table;
    default_kv.num =
        sizeof(default_kv_table) / sizeof(default_kv_table[0]);

    /* Printf save block information. */
    LOG("%s:fdb_tsdb size:%d \r\n", __FUNCTION__, sizeof(struct fdb_tsdb));
    LOG("%s:fdb_kvdb size:%d \r\n", __FUNCTION__, sizeof(struct fdb_kvdb));

    /* Clear data. */
    memset(&xTsdb, 0, sizeof(struct fdb_tsdb));
    memset(&xKvdb, 0, sizeof(struct fdb_kvdb));
    memset(&xKvdbUserInfor, 0, sizeof(struct fdb_kvdb));

    /* KVDB module initialization */
    fdb_kvdb_init(&xKvdb, "User", "kvdb1", &default_kv, NULL);
    /* KVDB user infor module initialization */
    fdb_kvdb_init(&xKvdbUserInfor, "User", "userInfor", NULL, NULL);

    /* time series initialize storage */
    fdb_tsdb_init(&xTsdb, "HsRec", "tsdb1", (fdb_get_time)uxTimeStampGet, 64, NULL);

    // tsdb_sample(&xTsdb);
    // kvdb_basic_sample(&xKvdb);
}

static bool query_cb(fdb_tsl_t tsl, void *arg)
{
    struct fdb_blob blob;
    ActionLog_t ActionLog;
    fdb_tsdb_t db = arg;

    fdb_blob_read((fdb_db_t)db, fdb_tsl_to_blob(tsl, fdb_blob_make(&blob, &ActionLog, sizeof(ActionLog))));
    // LOG("[query_cb] queried a TSL: time: %" __PRITS ", temp: %d, humi: %d\n", tsl->time, status.temp, status.humi);
    // LOG("[query_cb] queried a TSL: time: %d, ActionLog.temS (%X) and cont (%X)\n", tsl->time,ActionLog.timeStamp, ((ActionLog.Data<<16)+ActionLog.typeID));
    LOG("[query_cb] queried a TSL: time: %d, cont (%X)\n", tsl->time, ((ActionLog.Data << 16) + ActionLog.typeID));

    return false;
}

void tsdb_test_set(fdb_tsdb_t tsdb, uint32_t timestamp)
{
    struct fdb_blob blob;
    static ActionLog_t ActionLog;

    /* append new log to TSDB */
    // ActionLog.timeStamp = timestamp;
    ActionLog.typeID += 1;
    if (ActionLog.typeID == 0)
        ActionLog.Data += 1;
    fdb_tsl_append(tsdb, fdb_blob_make(&blob, &ActionLog, sizeof(ActionLog)));
    // LOG("append the new ActionLog.temS (%X) and Cont (%X)\n", ActionLog.timeStamp, ((ActionLog.Data<<16)+ActionLog.typeID));
    LOG("append the new Cont (%X)\n", ((ActionLog.Data << 16) + ActionLog.typeID));
}

void tsdb_test_QUERY(fdb_tsdb_t tsdb)
{
    fdb_tsl_iter(tsdb, query_cb, tsdb);
}

// static bool UserReadHistory_cb(fdb_tsl_t tsl, void *arg)
// {
//     struct fdb_blob blob;
//     ActionLog_t ActionLog;
//     fdb_tsdb_t db = arg;
//     Pillow_cmd_t    AckBleData;
//     uint8_t index = 0;

//     if(fdb_blob_read((fdb_db_t) db, fdb_tsl_to_blob(tsl, fdb_blob_make(&blob, &ActionLog, sizeof(ActionLog)))))
//     {
//         AckBleData.Head = PILLOW_SYNC_CMD;
//         AckBleData.prouctID = PILLOW_PID;
//         AckBleData.payloadLen = 6;
//         AckBleData.type = PILLOW_DATA_SYNC;
//         index = 0;
//         AckBleData.data[index++] = ActionLog.typeID&0xFF;
//         AckBleData.data[index++] = (tsl->time>>24)&0xFF;
//         AckBleData.data[index++] = (tsl->time>>16)&0xFF;
//         AckBleData.data[index++] = (tsl->time>>8)&0xFF;
//         AckBleData.data[index++] = (tsl->time)&0xFF;
//         if(ActionLog.typeID == PILLOW_InitialWeight || ActionLog.typeID == PILLOW_EndingWeight)
//         {
//             AckBleData.payloadLen = 8;
//             AckBleData.data[index++] = (ActionLog.Data>>8)&0xFF;
//             AckBleData.data[index++] = (ActionLog.Data)&0xFF;
//         }
//         index = AckBleData.payloadLen + 4;
//         AckBleData.data[AckBleData.payloadLen-1] = buff_AndCheck(&(AckBleData.prouctID),AckBleData.payloadLen+2);
//         Buff2UartStructdata(&ble_tx_data,(uint8_t *)&AckBleData,index);
//         peripheral_task_set(USER_TASK_START,USR_EVT_BLETX,30);
//     // LOG("[query_cb] queried a TSL: time: %d, cont (%X)\n", tsl->time,((ActionLog.Data<<16)+ActionLog.typeID));
//     }
//     return false;
// }

// bool Usertsdb_readHistory(bool fcontinue,fdb_tsdb_t db,fdb_time_t from, fdb_time_t to)
// {
//     static fdb_time_t fromTime = 0;
//     static fdb_time_t ToTime = 0;
//     fdb_time_t TimeNow = HalRtcGetUtcOnly();
//     bool ret = FALSE;
//     Pillow_cmd_t    AckBleData;
//     uint8_t index = 0;

//     static struct fdb_tsbd_OneByOne tsbdFindOneByOne= {
//         .found_start_tsl = FALSE,
//         .traversed_len = 0,
//     };
//     if(!fcontinue)
//     {
//         fromTime = from;
//         ToTime = to;
//         tsbdFindOneByOne.found_start_tsl = FALSE;
//         tsbdFindOneByOne.traversed_len = 0;
//         tsbdFindOneByOne.tsbd_flag = 0;
//     }
//     // return fdb_tsl_iter_by_time_OneOut(db,fromTime,ToTime,query_cb,db,&tsbdFindOneByOne);
//     // ret = fdb_tsl_iter_by_time_OneOut(db,fromTime,ToTime,UserReadHistory_cb,db,&tsbdFindOneByOne);
//     ret = fdb_tsl_iter_by_time_OneOut(db,fromTime,TimeNow,UserReadHistory_cb,db,&tsbdFindOneByOne);
//     if(ret == FALSE)
//     {
//         AckBleData.Head = PILLOW_SYNC_CMD;
//         AckBleData.prouctID = PILLOW_PID;
//         AckBleData.payloadLen = 6;
//         AckBleData.type = PILLOW_DATA_SYNC;
//         index = 0;
//         AckBleData.data[index++] = PILLOW_End;
//         AckBleData.data[index++] = (TimeNow>>24)&0xFF;
//         AckBleData.data[index++] = (TimeNow>>16)&0xFF;
//         AckBleData.data[index++] = (TimeNow>>8)&0xFF;
//         AckBleData.data[index++] = (TimeNow)&0xFF;
//         index = AckBleData.payloadLen + 4;
//         AckBleData.data[AckBleData.payloadLen-1] = buff_AndCheck(&(AckBleData.prouctID),AckBleData.payloadLen+2);
//         Buff2UartStructdata(&ble_tx_data,(uint8_t *)&AckBleData,index);
//         peripheral_task_set(USER_TASK_START,USR_EVT_BLETX,30);
//     }
//     return ret;
// }

void tsdb_sample(fdb_tsdb_t tsdb)
{
    struct fdb_blob blob;

    LOG("==================== tsdb_sample ====================\n");

    { /* APPEND new TSL (time series log) */
        ActionLog_t ActionLog;

        /* append new log to TSDB */
        // ActionLog.timeStamp = 0x0E2531;
        ActionLog.typeID = 1;
        fdb_tsl_append(tsdb, fdb_blob_make(&blob, &ActionLog, sizeof(ActionLog)));
        // LOG("append the new ActionLog.temS (%X) and ActionLog.ID (%X)\n", ActionLog.timeStamp, ActionLog.typeID);
        LOG("append the new ActionLog.ID (%X)\n", ActionLog.typeID);

        // ActionLog.timeStamp = 0x0E2531;
        ActionLog.typeID = 2;
        fdb_tsl_append(tsdb, fdb_blob_make(&blob, &ActionLog, sizeof(ActionLog)));
        // LOG("append the new ActionLog.temS (%X) and ActionLog.ID (%X)\n", ActionLog.timeStamp, ActionLog.typeID);
        LOG("append the new ActionLog.ID (%X)\n", ActionLog.typeID);
    }

    { /* QUERY the TSDB */
        /* query all TSL in TSDB by iterator */
        fdb_tsl_iter(tsdb, query_cb, tsdb);
    }

    // { /* QUERY the TSDB by time */
    //     /* prepare query time (from 1970-01-01 00:00:00 to 2020-05-05 00:00:00) */
    //     struct tm tm_from = { .tm_year = 1970 - 1900, .tm_mon = 0, .tm_mday = 1, .tm_hour = 0, .tm_min = 0, .tm_sec = 0 };
    //     struct tm tm_to = { .tm_year = 2020 - 1900, .tm_mon = 4, .tm_mday = 5, .tm_hour = 0, .tm_min = 0, .tm_sec = 0 };
    //     time_t from_time = mktime(&tm_from), to_time = mktime(&tm_to);
    //     size_t count;
    //     /* query all TSL in TSDB by time */
    //     fdb_tsl_iter_by_time(tsdb, from_time, to_time, query_by_time_cb, tsdb);
    //     /* query all FDB_TSL_WRITE status TSL's count in TSDB by time */
    //     count = fdb_tsl_query_count(tsdb, from_time, to_time, FDB_TSL_WRITE);
    //     LOG("query count is: %zu\n", count);
    // }

    // { /* SET the TSL status */
    //     /* Change the TSL status by iterator or time iterator
    //      * set_status_cb: the change operation will in this callback
    //      *
    //      * NOTE: The actions to modify the state must be in order.
    //      *       like: FDB_TSL_WRITE -> FDB_TSL_USER_STATUS1 -> FDB_TSL_DELETED -> FDB_TSL_USER_STATUS2
    //      *       The intermediate states can also be ignored.
    //      *       such as: FDB_TSL_WRITE -> FDB_TSL_DELETED
    //      */
    //     fdb_tsl_iter(tsdb, set_status_cb, tsdb);
    // }

    LOG("===========================================================\n");
}

void kvdb_basic_sample(fdb_kvdb_t kvdb)
{
    struct fdb_blob blob;
    int boot_count = 0;

    LOG("==================== kvdb_basic_sample ====================\n");

    { /* GET the KV value */
        /* get the "boot_count" KV value */
        fdb_kv_get_blob(kvdb, "boot_count", fdb_blob_make(&blob, &boot_count, sizeof(boot_count)));
        /* the blob.saved.len is more than 0 when get the value successful */
        if (blob.saved.len > 0)
        {
            LOG("get the 'boot_count' value is %d\n", boot_count);
        }
        else
        {
            LOG("get the 'boot_count' failed\n");
        }
    }

    { /* CHANGE the KV value */
        /* increase the boot count */
        boot_count++;
        /* change the "boot_count" KV's value */
        fdb_kv_set_blob(kvdb, "boot_count", fdb_blob_make(&blob, &boot_count, sizeof(boot_count)));
        LOG("set the 'boot_count' value to %d\n", boot_count);
    }

    LOG("===========================================================\n");
}
